package com.jy.api.util;

import com.aliyun.opensearch.DocumentClient;
import com.aliyun.opensearch.OpenSearchClient;
import com.aliyun.opensearch.SearcherClient;
import com.aliyun.opensearch.sdk.dependencies.com.google.common.collect.Lists;
import com.aliyun.opensearch.sdk.dependencies.org.json.JSONArray;
import com.aliyun.opensearch.sdk.dependencies.org.json.JSONObject;
import com.aliyun.opensearch.sdk.generated.OpenSearch;
import com.aliyun.opensearch.sdk.generated.commons.OpenSearchClientException;
import com.aliyun.opensearch.sdk.generated.commons.OpenSearchException;
import com.aliyun.opensearch.sdk.generated.commons.OpenSearchResult;
import com.aliyun.opensearch.sdk.generated.document.Command;
import com.aliyun.opensearch.sdk.generated.document.DocumentConstants;
import com.aliyun.opensearch.sdk.generated.search.Config;
import com.aliyun.opensearch.sdk.generated.search.SearchFormat;
import com.aliyun.opensearch.sdk.generated.search.SearchParams;
import com.aliyun.opensearch.sdk.generated.search.general.SearchResult;
import com.jy.api.vo.ProductVo;
import com.jy.api.vo.member.OpenSearchMemberVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

/**
 * Created by lihu on 2017/12/15.
 */
@Slf4j
public class OpenSearchUtil {

    private static final String appName = "hxy_opensearch";
    //会员应用名称
    private static final String memberName = "hxy_member";
    private static final String accesskey = "LTAI5tG68scB6Z7EwGY2Q1jx";
    private static final String secret = "P7NhOo4t9bqTr8fdJJ7wPW9q35OT70";
    private static final String host = "http://opensearch-cn-hangzhou.aliyuncs.com";

    private static OpenSearch openSearch = null;

    private static OpenSearchClient serviceClient = null;

    private static SearcherClient searcherClient = null;

    static {
        openSearch = new OpenSearch(accesskey, secret, host);
        //创建OpenSearchClient对象，并以OpenSearch对象作为构造参数
        serviceClient = new OpenSearchClient(openSearch);
        searcherClient = new SearcherClient(serviceClient);
    }


    /**
     * 单个商品同步
     *
     * @param map
     * @param appName
     * @param tableName
     */
    public static void push(Map<String, Object> map, String appName, String tableName) {
        //新增及更新都设为ADD，不支持update，当已存在相同主键值文档时做更新，否则新增，此处作为新增
        JSONArray docsJsonArr = new JSONArray();
        JSONObject json = new JSONObject();
        json.put(DocumentConstants.DOC_KEY_CMD, Command.ADD.toString());
        json.put(DocumentConstants.DOC_KEY_FIELDS, map);
        docsJsonArr.put(json);//新增文档1
        String docsJson = docsJsonArr.toString();
        log.info("{}", docsJson);

        try {
            DocumentClient documentClient = new DocumentClient(serviceClient);
            //执行推送操作
            OpenSearchResult osr = documentClient.push(docsJson, appName, tableName);
            //判断数据是否推送成功，主要通过判断2处，第一处判断用户方推送是否成功，第二处是应用控制台中有无报错日志
            //用户方推送成功后，也有可能在应用端执行失败，此错误会直接在应用控制台错误日志中生成，比如字段内容转换失败
            if (osr.getResult().equalsIgnoreCase("true")) {
                log.info("用户方推送无报错！\n以下为getTraceInfo推送请求Id:" + osr.getTraceInfo().getRequestId());
            } else {
                log.error("用户方推送报错！" + osr.getTraceInfo());
            }
        } catch (OpenSearchException e) {
            e.printStackTrace();
        } catch (OpenSearchClientException e) {
            e.printStackTrace();
        }

    }


    /**
     * 单个商品同步
     *
     * @param map
     * @param appName
     * @param tableName
     */
    public static void pushMaterial(Map<String, Object> map, String appName, String tableName) {
        //新增及更新都设为ADD，不支持update，当已存在相同主键值文档时做更新，否则新增，此处作为新增
        JSONArray docsJsonArr = new JSONArray();
        JSONObject json = new JSONObject();
        json.put(DocumentConstants.DOC_KEY_CMD, Command.ADD.toString());
        json.put(DocumentConstants.DOC_KEY_FIELDS, map);
        docsJsonArr.put(json);//新增文档1
        String docsJson = docsJsonArr.toString();
        log.info("{}", docsJson);

        try {
            DocumentClient documentClient = new DocumentClient(serviceClient);
            //执行推送操作
            OpenSearchResult osr = documentClient.push(docsJson, appName, tableName);
            //判断数据是否推送成功，主要通过判断2处，第一处判断用户方推送是否成功，第二处是应用控制台中有无报错日志
            //用户方推送成功后，也有可能在应用端执行失败，此错误会直接在应用控制台错误日志中生成，比如字段内容转换失败
            if (osr.getResult().equalsIgnoreCase("true")) {
                log.info("用户方推送无报错！\n以下为getTraceInfo推送请求Id:" + osr.getTraceInfo().getRequestId());
            } else {
                log.error("用户方推送报错！" + osr.getTraceInfo());
            }
        } catch (OpenSearchException e) {
            e.printStackTrace();
        } catch (OpenSearchClientException e) {
            e.printStackTrace();
        }

    }


    public static List<OpenSearchMemberVo> qureyMember(String storeId, String q) {
        List<OpenSearchMemberVo> memberVos = new ArrayList<>();
        //定义Config对象，用于设定config子句参数，分页或数据返回格式，指定应用名等等
        Config config = new Config(Lists.newArrayList(memberName));
        config.setStart(0);
        config.setHits(3);
        //设置返回格式为FULLJSON，目前支持返回 XML，JSON，FULLJSON 等格式
        config.setSearchFormat(SearchFormat.FULLJSON);
        // 设置搜索结果返回应用中哪些字段
        config.setFetchFields(Lists.newArrayList("id", "name", "code", "mobile", "store_id", "member_id"));

        // 创建参数对象
        SearchParams searchParams = new SearchParams(config);

        // 设置查询子句，若需多个索引组合查询，需要setQuery处合并，否则若设置多个setQuery后面的会替换前面查询
        searchParams.setQuery("(mobile:'" + q + "' OR code:'" + q + "') AND store_id:'" + storeId + "'");
        try {
            // 执行返回查询结果
            SearchResult searchResult = searcherClient.execute(searchParams);
            String result = searchResult.getResult();
            JSONObject obj = new JSONObject(result);
            JSONObject object = obj.getJSONObject("result");
            if (StringUtils.equals(obj.getString("status"), "OK")) {
                JSONArray jsonArray = object.getJSONArray("items");
                for (int i = 0; i < jsonArray.length(); i++) {
                    JSONObject jsonObject = (JSONObject) jsonArray.get(i);
                    JSONObject object1 = (JSONObject) jsonObject.get("fields");
                    memberVos.add(new OpenSearchMemberVo(object1.getString("id"),
                            object1.getString("code"),
                            object1.getString("mobile"),
                            object1.getString("name"),
                            object1.getString("store_id"),
                            object1.getString("member_id")));
                }
            }
        } catch (OpenSearchException e) {
            e.printStackTrace();
        } catch (OpenSearchClientException e) {
            e.printStackTrace();
        }
        return memberVos;

    }

    /**
     * @param storeId
     * @param q
     * @param status  是否查看上下架功能
     * @return
     */
    public static List<ProductVo> queryProduct(String storeId, String q, boolean status) {
        List<ProductVo> products = new ArrayList<>();
        //定义Config对象，用于设定config子句参数，分页或数据返回格式，指定应用名等等
        Config config = new Config(Lists.newArrayList(appName));
        config.setStart(0);
        config.setHits(5);
        //设置返回格式为FULLJSON，目前支持返回 XML，JSON，FULLJSON 等格式
        config.setSearchFormat(SearchFormat.FULLJSON);
        // 设置搜索结果返回应用中哪些字段
        config.setFetchFields(Lists.newArrayList("id", "name", "store_id"));

        // 创建参数对象
        SearchParams searchParams = new SearchParams(config);

        // 设置查询子句，若需多个索引组合查询，需要setQuery处合并，否则若设置多个setQuery后面的会替换前面查询
        searchParams.setQuery("name:'" + q + "'");
        if (status) {
            searchParams.setFilter("store_id=\"" + storeId + "\"AND product_status=\"0\"AND is_enabled=\"1\"");
        } else {
            searchParams.setFilter("store_id=\"" + storeId + "\"AND is_enabled=\"1\"");
        }

        try {
            // 执行返回查询结果
            SearchResult searchResult = searcherClient.execute(searchParams);
            String result = searchResult.getResult();
            JSONObject obj = new JSONObject(result);
            JSONObject object = obj.getJSONObject("result");
            if (StringUtils.equals(obj.getString("status"), "OK")) {
                JSONArray jsonArray = object.getJSONArray("items");
                for (int i = 0; i < jsonArray.length(); i++) {
                    JSONObject jsonObject = (JSONObject) jsonArray.get(i);
                    JSONObject object1 = (JSONObject) jsonObject.get("fields");
                    products.add(new ProductVo(object1.getString("id"), object1.getString("name"),new HashSet<>()));
                }
            }
        } catch (OpenSearchException e) {
            e.printStackTrace();
        } catch (OpenSearchClientException e) {
            e.printStackTrace();
        }

        return products;
    }
}